<template>
  <div class="app">
    <!-- 返回按钮 -->
    <button @click="goBack" class="back-button">返回</button>
    <h1>测试步骤编辑器</h1>
    <div class="editor-container">
      <!-- 左侧操作控件面板 -->
      <div class="control-panel">
        <h2>操作控件</h2>
        <div
          v-for="control in controls"
          :key="control.type"
          class="control"
          draggable="true"
          @dragstart="onDragStart(control, $event)"
        >
          <span class="icon">{{ control.icon }}</span>
          {{ control.label }}
        </div>
      </div>

      <!-- 右侧测试步骤编辑区域 -->
      <div class="steps-panel">
        <h2>测试步骤</h2>
        <draggable style="min-height: 500px;" v-model="steps" item-key="id" group="steps" @drop="onDrop" @dragover.prevent="onDragOver">
          <template #item="{ element }">
            <div class="step">
              <div class="step-header">
                <span class="icon">{{ getIcon(element.type) }}</span>
                <span>{{ getLabel(element.type) }}</span>
                <button @click="confirmDeleteStep(element.id)" class="delete-button">删除</button>
              </div>
              <!-- 直接嵌入 TestStepEditor 的内容 -->
              <div class="test-step-editor">
                <!-- 鼠标点击控件 -->
                <div v-if="element.type === 'click'" class="click-step">
                  <div class="input-row">
                    <div class="input-group">
                      <label>鼠标按钮：</label>
                      <select
                        :value="element.value"
                        @change="updateStep(element.id, 'value', $event.target.value)"
                      >
                        <option value="left">左键</option>
                        <option value="middle">中键</option>
                        <option value="right">右键</option>
                      </select>
                      <select
                        :value="element.value1"
                        @change="updateStep(element.id, 'value1', $event.target.value)"
                      >
                        <option value="press">单击</option>
                        <option value="double_press">双击</option>
                      </select>
                    </div>
                  </div>
                  <div style="display:flex;align-items:center;gap:10px;">
                    <div>
                      <span class="highlight">{{ element.value === 'left' ? '左键' : element.value === 'middle' ? '中键' : '右键' }}</span>
                      点击
                    </div>
                    <div v-if="element.imageName">
                      <el-image :src="getCapture(element.imageName)" fit="contain" style="width: 30px; height: 30px;"></el-image>
                    </div>
                    <div v-else>
                      <!-- 显示文件选择按钮 -->
                      <input type="file" @change="(e)=>onFileChange(e, element)" />
                    </div>
                  </div>
                </div>
                <!-- 输入文本控件 -->
                <div v-if="element.type === 'scroll'" class="step-content">
                  <label>鼠标滚动：</label>
                  <input
                    :value="element.value"
                    type="number"
                    @input="updateStep(element.id, 'value', $event.target.value)"
                  />
                  <div style="display:flex;align-items:center;gap:10px;">
                    <div>
                      在输入框输入文本
                      <span class="highlight">‘{{ element.value || ' ' }}’</span>
                    </div>
                  </div>
                </div>
                <!-- 输入文本控件 -->
                <div v-if="element.type === 'type'" class="step-content">
                  <label>文本内容：</label>
                  <input
                    :value="element.value"
                    @input="updateStep(element.id, 'value', $event.target.value)"
                  />
                  <div style="display:flex;align-items:center;gap:10px;">
                    <div>
                      在输入框输入文本
                      <span class="highlight">‘{{ element.value || ' ' }}’</span>
                    </div>
                  </div>
                </div>

                <!-- 键盘按键控件 -->
                <div v-if="element.type === 'press'" class="step-content">
                  <label>按键：</label>
                  <input
                    :value="element.value"
                    @input="($event)=>handleInput($event, element.id, 'value', $event.target.value)"
                  />
                  
                  <div style="display:flex;align-items:center;gap:10px;">
                    <div>
                      按下键盘上的
                      <span class="highlight">‘{{ element.value || ' ' }}’</span>
                      键
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </template>
        </draggable>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import draggable from 'vuedraggable';
import { useRouter,useRoute } from 'vue-router';
import { apiInfoTestcase, apiUploadContentTestcase, apiUploadTestcase } from '@/api/testcase';
import JSZip from "jszip";
import { ElMessage, ElMessageBox } from 'element-plus';

const props = defineProps(['id']);

const controls = ref([
  { type: 'click', label: '鼠标点击', icon: '🖱️' },
  { type: 'scroll', label: '鼠标滚动', icon: '🎨' },
  { type: 'type', label: '文本输入', icon: '⌨️' },
  { type: 'press', label: '键盘按键', icon: '🔑' },
]);
const closestItemIndex = ref(-1)
const recordFile = ref(null)
const imageFiles = ref([])
const nowRelativePath = ref('')

const steps = ref([]);

const router = useRouter(); // 使用 Vue Router 的 useRouter 钩子
const route = useRoute(); // 使用 Vue Router 的 useRoute 钩子

onMounted(async () => {
  // 获取测试步骤数据
  const filename = route.query.filename;
  if (filename) {
    nowRelativePath.value = filename
    await getZip(filename)
  }
});

const onFileChange = (e, row) => {

  let idx = steps.value.findIndex((step) => step.id === row.id);
  if (idx === -1) {
    return;
  }
  const file = e.target.files[0];
  const reader = new FileReader();
  reader.onload = (e) => {
    const base64 = e.target.result;
    const filename = Date.now() + '.png'
    imageFiles.value.push({
      name: filename,
      url: base64,
    });
    steps.value[idx].imageName = filename;
  };
  reader.readAsDataURL(file);
}

const getLabel = (type) => {
  let idx = controls.value.findIndex((control) => control.type === type);
  if (idx === -1) {
    return '';
  }
  return controls.value[idx].label;
}

const getCapture = (name) => {
  let idx = imageFiles.value.findIndex((image) => {
    return image.name.startsWith(name);
  });
  if (idx === -1) {
    return '';
  }
  return imageFiles.value[idx].url;
}

const getZip = async(filename)=>{
  const res = await apiInfoTestcase(filename)
  await parseZip(res)
}

const parseZip = async(file) => {
  const zip = new JSZip();
  const zipContents = await zip.loadAsync(file); // Parse the ZIP file
  // Iterate over the files in the zip using zip.files (assuming JSZip)
  for (const zipEntry of Object.entries(zipContents.files)) {
    const [relativePath, entry] = zipEntry;
    
    if (entry.dir) {
      // nowRelativePath.value = relativePath
    } else {
      // Check if it's an image file
      if (isImageFile(entry.name)) {
        // Await the async operation
        const base = await entry.async("base64");
        imageFiles.value.push({
          name: entry.name.split("/").pop(),
          url: `data:image/png;base64,${base}`
        });
      }
      if (entry.name.endsWith("record.txt")) {
        recordFile.value = entry;
      }
    }
  }
  printRecordFile()
}

const isImageFile = (filename) => {
  const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
  const extension = filename.toLowerCase().slice(((filename.lastIndexOf(".") - 1) >>> 0) + 2);
  return imageExtensions.includes(`.${extension}`);
};

const printRecordFile = async () => {
  if (!recordFile.value) {
    console.log("没有找到 record.txt 文件");
    return;
  }
  try {
    // 读取 record.txt 文件的内容
    const fileContent = await recordFile.value.async("text");

    // 按行分割文件内容
    const lines = fileContent.split("\n");

    // 逐行打印
    lines.forEach((line, index) => {
      const content= line.split(',')
      console.log(line)
      // 创建一个 base64 URL，并设置为 img 标签的 src
      if (content.length === 2) {
        steps.value.push({
          type: content[0],
          value: content[1],
          id: index
        })
      } else if (content.length == 4){
        steps.value.push({
          type: content[0],
          imageName: `${content[1]}.png`,
          value: content[2],
          value1: content[3],
          id: index
        })
      }
    });
  } catch (error) {
    console.error("读取文件失败:", error);
  }
};

function extractFilenamePart(filename) {
  // 正则表达式：匹配路径中最后一个斜杠后面的部分，直到扩展名
  const match = filename.match(/\/([^\/]+)(?=\.[a-z]+$)/);

  if (match) {
    return match[1];  // 返回提取到的文件名部分
  }
  return null;  // 如果没有匹配到，返回 null
}

const onDragStart = (control, event) => {
  event.dataTransfer.setData('control', JSON.stringify(control));
};

const confirmDeleteStep = (id) => {
  // 确认删除步骤
  if (confirm('确定要删除该步骤吗？')) {
    deleteStep(id);
  }
};

const deleteStep = (id) => {
  steps.value = steps.value.filter((step) => step.id !== id);
};

const allowOnlyAlphaNumeric = (event) => {
  const key = event.key;
  if (!/^[a-zA-Z0-9]$/.test(key) && key !== "Backspace") {
    event.preventDefault(); // 阻止输入非法字符
  }
};

const handleInput = (event, id, key, value) => {
  // 允许的字符（数字、字母和空格）
  const regex = /^[a-zA-Z0-9 ]*$/;
  const inputValue = event.target.value;
  
  // 如果输入的值不匹配正则，回退到上一个值
  if (!regex.test(inputValue)) {
    const step = steps.value.find((step) => step.id === id);
    if (step) {
      event.target.value = step[key]
    }
  } else {
    updateStep(id, key, value);
  }
}

const updateStep = (id, key, value) => {
  const step = steps.value.find((step) => step.id === id);
  if (step) {
    step[key] = value;
  }
};

const onDrop = (event) => {
  event.preventDefault();
  const controlData = event.dataTransfer.getData('control');
  if (!controlData) {
    console.error('拖拽数据为空');
    return;
  }
  try {
    if (closestItemIndex.value === -1) {
      closestItemIndex.value = steps.value.length;
    }
    const control = JSON.parse(controlData);
    steps.value.splice(closestItemIndex.value, 0, {
      imageName: '',
      id: Date.now(),
      type: control.type,
      value: '', // 默认按钮值
      value1:''
    });
    closestItemIndex.value = -1;
  } catch (error) {
    console.error('解析拖拽数据失败:', error);
  }
};

const onDragOver = (event) => {
  event.preventDefault();
  const draggableItems = event.currentTarget.children; // 获取所有子项
  const mouseY = event.clientY; // 获取鼠标 Y 坐标
  let closestDistance = Number.MAX_VALUE;

  // 遍历每个子项，计算鼠标 Y 坐标和每个子项的垂直距离
  for (let i = 0; i < draggableItems.length; i++) {
    const item = draggableItems[i];
    const rect = item.getBoundingClientRect(); // 获取子项的位置
    const distance = Math.abs(mouseY - rect.top - rect.height / 2); // 计算与中间点的距离

    if (distance < closestDistance) {
      closestDistance = distance;
      closestItemIndex.value = i; // 找到距离最近的子项索引
    }
  }
};

const getIcon = (type) => {
  const control = controls.value.find((c) => c.type === type);
  return control ? control.icon : '';
};

const checkImageValid = () => {
  for (let i = 0 ; i < steps.value.length; i++) {
    if (steps.value[i].type === 'click') {
      if(steps.value[i].imageName === '')return false
    }
  };
  return true
}

const geneTxtFile = (content, fileName = "record.txt") => {
  // 创建 Blob
  const blob = new Blob([content], { type: "text/plain" });

  // 生成 File 对象
  const file = new File([blob], fileName, { type: "text/plain" });
  recordFile.value = file
};

const goBack = async() => {
  ElMessageBox.confirm(
    '是否返回上一页并保存数据?',
    '警告',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  )
    .then(async () => {
      await toBack()
    })
};

const toBack = async() => {
  if (!checkImageValid()) {
    alert('请上传所有图片')
    return
  }
  genText()
  // 重新开始
  await uploadZip()
  // 返回上一页
  router.go(-1);
}

const genText = () => {
  let content = ''
  steps.value.forEach((step) => {
    if(step.type === 'click'){
      let imageName = step.imageName.split('.')[0]
      content += `${step.type},${imageName},${step.value},${step.value1}\n`
    }else {
      content += `${step.type},${step.value}\n`
    }    
  });
  geneTxtFile(content)
}

const uploadZip = async () => {
  const zip = new JSZip();

  // 1️⃣ 处理 Base64 图片
  for (const img of imageFiles.value) {
    const base64Data = img.url.split(",")[1]; // 去掉 data:image/png;base64,
    const binaryData = atob(base64Data); // Base64 转二进制
    const uint8Array = new Uint8Array(binaryData.length);
    for (let i = 0; i < binaryData.length; i++) {
      uint8Array[i] = binaryData.charCodeAt(i);
    }
    zip.file(img.name, uint8Array); // 添加到 ZIP
  }
  // 2️⃣ 处理 File 对象
  zip.file(recordFile.value.name, recordFile.value);

  // 3️⃣ 生成 ZIP 文件（Blob）
  const zipBlob = await zip.generateAsync({ type: "blob" });

  // 4️⃣ 上传到服务器
  const formData = new FormData();
  formData.append("file", new File([zipBlob], `${nowRelativePath.value}`, { type: "application/zip" }));
  apiUploadContentTestcase(formData)
  .then((res) => {
    ElMessage.success('上传成功')
    console.log("上传成功:", res);
  })
  .catch((error) => {
    console.error("上传失败:", error);
  });
};
</script>

<style scoped>
.app {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  padding: 20px;
  background-color: #f4f4f9;
  color: #333;
}

h1 {
  text-align: center;
  color: #4a4a4a;
}

.editor-container {
  display: flex;
  gap: 20px;
}

.control-panel, .steps-panel {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background-color: #fff;
  height: 600px;
  overflow: auto;
}

.control-panel {
  width: 220px;
}

.control {
  padding: 12px;
  margin-bottom: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background-color: #fafafa;
  cursor: grab;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 8px;
}

.control:hover {
  background-color: #e6e6e6;
}

.steps-panel {
  flex: 1;
}

.step {
  padding: 15px;
  margin-bottom: 15px;
  border: 1px solid #ccc;
  border-radius: 6px;
  background-color: #fafafa;
}

.step-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.delete-button {
  padding: 5px 10px;
  border: none;
  border-radius: 4px;
  background-color: #ff4d4f;
  color: #fff;
  cursor: pointer;
  margin-left: auto;
}

.delete-button:hover {
  background-color: #d9363e;
}

.back-button {
  padding: 5px 10px;
  border: none;
  border-radius: 4px;
  background-color: #409eff;
  color: #fff;
  cursor: pointer;
  margin-bottom: 20px;
}

.back-button:hover {
  background-color: #337ecc;
}

.icon {
  font-size: 16px;
}

.test-step-editor {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.click-step {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.input-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.input-group {
  display: flex;
  align-items: center;
  gap: 8px;
}

label {
  font-weight: 500;
  color: #333;
  min-width: 50px;
}

input[type="number"],
select {
  padding: 6px 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 14px;
  width: 100px;
}

input[type="number"]:focus,
select:focus {
  outline: none;
  border-color: #409eff;
  box-shadow: 0 0 4px rgba(64, 158, 255, 0.3);
}

p {
  margin-top: 10px;
  font-size: 14px;
  color: #666;
}

.highlight {
  color: #409eff;
  font-weight: 500;
}
</style>